package controller

import (
	"ci-control-backend/common/db"
	"ci-control-backend/common/hostConn"
	"ci-control-backend/common/httpx"
	"ci-control-backend/model"
	"ci-control-backend/tools"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"log"
	"time"
)

type HostController struct{}

func (*HostController) NewHost(ctx *httpx.Context) any {
	var req struct {
		HostName string `json:"host_name"`
		Remark   string `json:"remark"`
	}

	if err := ctx.ShouldBindJSON(&req); err != nil {
		return errors.WithStack(err)
	}

	if req.HostName == "" {
		return errors.New("主机名不能为空")
	}

	keys, _ := tools.RandomStr(64)
	host := model.Host{HostName: req.HostName, Remark: req.Remark, Keys: keys}
	if _, err := host.Insert(); err != nil {
		return errors.WithStack(err)
	}

	return "添加成功"
}

func (*HostController) DelHost(ctx *httpx.Context) any {
	id := ctx.ParamUint("id")
	host, err := model.GetHostByID(id)
	if err != nil {
		return errors.WithStack(err)
	}
	if host == nil {
		return errors.Errorf("不存在id=%v的主机", id)
	}
	if _, err := host.Delete(); err != nil {
		return errors.WithStack(err)
	}
	return "删除成功"
}

func (*HostController) UpdateHost(ctx *httpx.Context) any {
	var req struct {
		HostName string `json:"host_name"`
		Remark   string `json:"remark"`
	}

	if err := ctx.ShouldBindJSON(&req); err != nil {
		return errors.WithStack(err)
	}

	id := ctx.ParamUint("id")
	host, err := model.GetHostByID(id)

	if err != nil {
		return errors.WithStack(err)
	}
	if host == nil {
		return errors.Errorf("不存在id=%v的主机", id)
	}

	if req.HostName == "" && req.Remark == "" {
		return errors.New("参数错误")
	}

	if req.HostName != "" {
		host.HostName = req.HostName
	}

	if req.Remark != "" {
		host.Remark = req.Remark
	}

	if _, err := host.Update(); err != nil {
		return errors.WithStack(err)
	}

	return "修改成功"
}

func (*HostController) GetHostList(ctx *httpx.Context) any {
	var page, pageSize int
	err := ctx.MultiQuery(gin.H{
		"page":     &page,
		"pageSize": &pageSize,
	})
	if err != nil {
		return err
	}

	// 分页查询
	pageable := db.QueryPage(&model.Host{})
	pageResult, err := pageable.PageParam(page, pageSize).Exec()
	if err != nil {
		return err
	}
	for _, host := range pageResult.PageData {
		host.Keys = ""
	}
	return pageResult
}

// Channel 建立SSE连接通道
func (*HostController) Channel(ctx *httpx.Context) any {
	keys := ctx.Param("key")
	if keys == "" {
		return errors.New("密钥不允许为空")
	}
	host, err := model.GetHostByKeys(keys)
	if err != nil {
		return errors.WithStack(err)
	}
	if host == nil {
		return errors.Errorf("主机密钥错误：%v", keys)
	}

	// 保存连接信息，这些信息能够被其他API接口使用
	hostConn.Add(host, ctx)
	// 推迟至方法退出时执行，将主机从连接队列中删除
	defer hostConn.Del(host)

	// 构建SSE通道
	ctx.Writer.Header().Set("Content-Type", "text/event-stream")
	i := 0
	for {
		select {
		// 如果是主机主动断开了连接，将终止执行之后的步骤
		case <-ctx.Request.Context().Done():
			return nil
		// 默认情况下将执行以下代码段
		default:
			i += 1
			log.Println(i)
			// 向主机发送一条消息，检测主机的心跳
			ctx.SSEvent("message", gin.H{
				"type": "hello",
			})
			// 清空缓存，立即发送所有数据
			ctx.Writer.Flush()
			// 暂停10s
			time.Sleep(10 * time.Second)
		}
	}
}

func (*HostController) ReportStatus(ctx *httpx.Context) any {
	keys := ctx.Param("key")
	if keys == "" {
		return errors.New("密钥不允许为空")
	}
	host, err := model.GetHostByKeys(keys)
	if err != nil {
		return errors.WithStack(err)
	}
	if host == nil {
		return errors.Errorf("主机密钥错误：%v", keys)
	}

	// 记录消息到达的时间，并保存
	host.LastOnlineTime = tools.TimePtr(time.Now())
	if _, err := host.Update(); err != nil {
		return errors.WithStack(err)
	}

	return "上报成功"
}

func (*HostController) GetHookKey(ctx *httpx.Context) any {
	var id uint
	err := ctx.Query("id", &id)
	if err != nil {
		return errors.WithStack(err)
	}

	if id == 0 {
		return errors.New("id不允许为空")
	}

	host, err := model.GetHostByID(id)
	if err != nil {
		return errors.WithStack(err)
	}
	if host == nil {
		return errors.Errorf("不存在id=%v的主机", id)
	}

	return gin.H{"key": host.Keys}
}
